package com.api.aiyh_pcn.fadada.service.impl;

import aiyh.utils.Util;
import aiyh.utils.entity.ApiConfigDetailDTO;
import aiyh.utils.entity.ApiConfigMainDTO;
import aiyh.utils.httpUtil.ResponeVo;
import aiyh.utils.mapUtil.ParaMap;
import aiyh.utils.sqlUtil.sqlResult.impl.PrepSqlResultImpl;
import aiyh.utils.zwl.common.ToolUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.api.aiyh_pcn.fadada.dao.FaDDContractMapping;
import com.api.aiyh_pcn.fadada.entity.FaDaDaConfigDTO;
import com.api.aiyh_pcn.fadada.entity.PushAPushEmailEntity;
import com.api.aiyh_pcn.fadada.entity.UfContractInfoDTO;
import com.api.aiyh_pcn.fadada.util.FaDDRequestUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.axiom.util.base64.Base64Utils;
import org.apache.http.HttpEntity;
import org.h2.util.StringUtils;
import weaver.conn.RecordSet;
import weaver.email.EmailWorkRunnable;
import weaver.general.xcommon.IOUtils;
import weaver.hrm.User;
import weaver.soa.workflow.FileProcessor;
import weaver.workflow.workflow.WorkflowVersion;

import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author EBU7-dev1-ayh
 * @create 2021/11/3 0003 14:51
 */
public class FaDDContractService {
    private final ToolUtil toolUtil = new ToolUtil();
    private final String contractInfoTable = "uf_contract_info";
    private final FaDDContractMapping faDDContractMapping = new FaDDContractMapping();

    /**
     * 获取全版本的流程id，节点id
     *
     * @param workflowId
     * @return
     */
    public Map<String, Object> getAllVersion(String workflowId) {
        String versionStringByWfid = WorkflowVersion.getVersionStringByWfid(workflowId);
        String newWorkflowId = faDDContractMapping.getAllVersion(versionStringByWfid);
        String allVersion = WorkflowVersion.getVersionStringByWfid(newWorkflowId);
        if (allVersion == null) {
            allVersion = "";
        }
        String[] split = allVersion.split(",");
        Map<String, Object> data = new HashMap<>();
        String[] nodes = this.getNodes(workflowId);
        data.put("workflowIds", split);
        data.put("nodeIds", nodes);
        return data;
    }

    /**
     * 获取节点id
     *
     * @param workflowId
     * @return
     */
    public String[] getNodes(String workflowId) {
        String versionStringByWfid = WorkflowVersion.getVersionStringByWfid(workflowId);
        String nods = faDDContractMapping.getNodes(versionStringByWfid);
        if (nods == null) {
            nods = "";
        }
        return nods.split(",");
    }

    /**
     * 获取替换SQL的数据
     *
     * @param requestId
     * @param workflowId
     * @param mainTableName
     * @param tableName
     * @return
     */
    public List<Map<String, Object>> getDataArr(
            String requestId, String workflowId, String mainTableName, String tableName) {
        Map<String, Object> mainMap = faDDContractMapping.queryMainMap(requestId, mainTableName);
        String mainId = Util.null2String(mainMap.get("id"));
        List<Map<String, Object>> detailMaps = faDDContractMapping.queryDetailMaps(mainId, tableName);
        return getDataArr(requestId, workflowId, tableName, mainMap, detailMaps);
    }

    public List<Map<String, Object>> getDataArr(
            String requestId,
            String workflowId,
            String mainTableName,
            String tableName,
            List<Map<String, Object>> detailMaps) {
        Map<String, Object> mainMap = faDDContractMapping.queryMainMap(requestId, mainTableName);
        String mainId = Util.null2String(mainMap.get("id"));
        return getDataArr(requestId, workflowId, tableName, mainMap, detailMaps);
    }

    public List<Map<String, Object>> getDataArr(
            String requestId,
            String workflowId,
            String tableName,
            Map<String, Object> mainMap,
            List<Map<String, Object>> detailMaps) {
        List<Map<String, Object>> dataArr = new ArrayList<>();
        String dt = tableName.substring(tableName.indexOf("_dt") + 3);
        String main = "main.";
        String detail = "detail_" + dt + ".";
        for (Map<String, Object> detailMap : detailMaps) {
            Map<String, Object> data = new HashMap<>();
            for (Map.Entry<String, Object> entry : mainMap.entrySet()) {
                data.put(main + entry.getKey(), entry.getValue());
            }
            for (Map.Entry<String, Object> entry : detailMap.entrySet()) {
                data.put(detail + entry.getKey(), entry.getValue());
            }
            data.put("requestId", requestId);
            data.put("workflowId", workflowId);
            dataArr.add(data);
        }
        return dataArr;
    }

    /**
     * 获取处理object和List类型后的参数
     *
     * @param treeList
     * @param dataArr
     * @return
     */
    public List<Map<String, Object>> objectAndListHandle(
            List<ApiConfigDetailDTO> treeList, List<Map<String, Object>> dataArr) {
        List<Map<String, Object>> params = new ArrayList<>();
        for (Map<String, Object> dataMap : dataArr) {
            Map<String, Object> param = new HashMap<>();
            for (ApiConfigDetailDTO apiConfigDetailDTO : treeList) {
                Object value;
                if (apiConfigDetailDTO.getParamType() == 3) {
                    Map<String, Object> map = new HashMap<>();
                    //                  object类型
                    for (ApiConfigDetailDTO child : apiConfigDetailDTO.getChildren()) {
                        if (child.getChildren() == null || child.getChildren().size() == 0) {
                            //							  handleChild(child.getChildren(), dataMap)
                            map.put(child.getParamName(), changeRuleHandle(child, dataMap));
                        } else {
                            map.put(child.getParamName(), handleChild(child.getChildren(), dataMap));
                        }
                    }
                    value = map;
                } else if (apiConfigDetailDTO.getParamType() == 4) {
                    String sql = apiConfigDetailDTO.getArraySql();
                    String parsingSq = aiyh.utils.Util.parsingSq(sql, dataMap);
                    //				    list类型
                    if (parsingSq.contains("delete")
                            || parsingSq.contains("update")
                            || parsingSq.contains("exec")
                            || parsingSq.contains("drop")
                            || parsingSq.contains("truncate")) {
                        value = new ArrayList<>();
                    } else {
                        RecordSet rs = new RecordSet();
                        String replace =
                                parsingSq
                                        .replace("ｓｅｌｅｃｔ ", "select ")
                                        .replaceAll(" ａｎｄ ", " and ")
                                        .replaceAll(" ｏｒ ", " or ")
                                        .replaceAll(" ｊｏｉｎ ", " join ")
                                        .replaceAll(" ｉｎ ", " in ");
                        rs.executeQuery(replace);
                        value = aiyh.utils.Util.recordeSet2Array(rs, String.class);
                    }
                } else {
                    value = changeRuleHandle(apiConfigDetailDTO, dataMap);
                }
                param.put(apiConfigDetailDTO.getParamName(), value);
            }
            params.add(param);
        }
        return params;
    }

    /**
     * 处理子类
     *
     * @param children
     * @param dataMap
     * @return
     */
    private Object handleChild(List<ApiConfigDetailDTO> children, Map<String, Object> dataMap) {
        Map<String, Object> params = new HashMap<>();
        for (ApiConfigDetailDTO child : children) {
            Object value;
            if (child.getChildren() != null) {
                value = handleChild(child.getChildren(), dataMap);
            } else {
                value = changeRuleHandle(child, dataMap);
            }
            params.put(child.getParamName(), value);
        }
        return params;
    }

    /**
     * 根据转换规则生成对应的参数值
     *
     * @param apiConfigDetailDTO
     * @param dataMap
     * @return
     */
    private Object changeRuleHandle(
            ApiConfigDetailDTO apiConfigDetailDTO, Map<String, Object> dataMap) {
        Object value;
        String tableName;
        String table;
        String sql;
        String resultSql;
        //			判断参数的转换规则
        switch (apiConfigDetailDTO.getChangeRule()) {
            case 0:
                //					不转换
            case 2:
                //					流程字段值
                table = apiConfigDetailDTO.getTablename();
                if (!table.contains("_dt")) {
                    //			        表示字段属于主表
                    tableName = "main";
                } else {
                    //			        字段属于明细表
                    String dt = table.substring(table.indexOf("_dt") + 3);
                    tableName = "detail_" + dt;
                }
                value = dataMap.get(tableName + "." + apiConfigDetailDTO.getWorkflowField());
                break;
            case 1:
                //					固定值
                value = apiConfigDetailDTO.getParamValue();
                break;
            case 3:
                //					系统日期
                value = aiyh.utils.Util.getTime("yyyy-MM-dd");
                break;
            case 4:
                //					系统时间
                value = aiyh.utils.Util.getTime("HH:mm:ss");
                break;
            case 5:
                //					系统日期-时间
                value = aiyh.utils.Util.getTime("yyyy-MM-dd HH:mm:ss");
                break;
            case 6:
                //					自定义SQL
            case 7:
                //					流程字段转SQL
                sql = apiConfigDetailDTO.getParamValue();
                resultSql = aiyh.utils.Util.parsingSq(sql, dataMap);
                if (resultSql.contains("delete ")
                        || resultSql.contains("update ")
                        || resultSql.contains("exec ")
                        || resultSql.contains("drop ")
                        || resultSql.contains("truncate ")) {
                    value = null;
                } else {
                    RecordSet rs = new RecordSet();
                    String replace =
                            resultSql
                                    .replace("ｓｅｌｅｃｔ ", "select ")
                                    .replaceAll(" ａｎｄ ", " and ")
                                    .replaceAll(" ｏｒ ", " or ")
                                    .replaceAll(" ｊｏｉｎ ", " join ")
                                    .replaceAll(" ｉｎ ", " in ");
                    rs.executeQuery(replace);
                    rs.next();
                    value = aiyh.utils.Util.null2String(rs.getString(1));
                }
                break;
            case 8:
                //
                //					流程名称
                value = aiyh.utils.Util.getWorkflowNameById(String.valueOf(dataMap.get("workflowid")));
                break;
            case 9:
                //
                //					请求标题
                value = aiyh.utils.Util.getRequestTitleById(String.valueOf(dataMap.get("requestid")));
                break;
            case 10:
                //					流程requestId
                value = dataMap.get("requestid");
                break;
            default:
                value = null;
                break;
        }
        if (apiConfigDetailDTO.getParamType() == 1) {
            //			Integer
            value = Integer.parseInt(String.valueOf(value));
        } else if (apiConfigDetailDTO.getParamType() == 2) {
            //          Boolean
            value = Boolean.parseBoolean(String.valueOf(value));
        }
        return value;
    }

    /**
     * 合同签署回调逻辑处理
     *
     * @param contractNo
     */
    public void signedCallBack(String contractNo) {
        //		查询合同信息表中的数据
        UfContractInfoDTO ufContractInfoDTO = faDDContractMapping.queryContractInfo(contractNo);
        toolUtil.writeDebuggerLog("回调，获取到合同信息参数：" + JSON.toJSONString(ufContractInfoDTO));
        Map<String, Object> update = new HashMap<>();
        if (ufContractInfoDTO.getQueueSigned() == 1) {
            //			属于顺序签署合同,更新单份合同已签蜀几个文件
            update.put("single_signed_num", ufContractInfoDTO.getSingleSignedNum() + 1);
            toolUtil.writeDebuggerLog("单份合同签署成功");
            //			如果单份合同签署数量等于合同文件数量，表示已经签署完成
            if (ufContractInfoDTO.getSingleSignedNum() + 1
                    == ufContractInfoDTO.getSingleContractFileNum()) {
                toolUtil.writeDebuggerLog("单份合同全部签署成功");
                update.put("signed_num", ufContractInfoDTO.getSignedNum() + 1);
                //				查询下一位合同方并发起签署
                if (ufContractInfoDTO.getSignedNum() + 1 < ufContractInfoDTO.getShouldSignedNum()) {
                    toolUtil.writeDebuggerLog(
                            "应签署合同比签署合同数量多，需要再次签署！" + (ufContractInfoDTO.getSignedNum() + 1));
                    update.put("single_signed_num", 0);
                    nextContractSigned(ufContractInfoDTO);
                }
            }
            //			如果合同已签数量和应签数量相同，则状态为本方待签
            if (ufContractInfoDTO.getSignedNum() + 1 == ufContractInfoDTO.getShouldSignedNum()) {
                update.put("contract_status", 3);
                //		判断是否控制签署规则 1-仅本方签署，2-仅对方签署，3-都签署
                if ("1".equals(Util.null2String(ufContractInfoDTO.getSignedType()))) {
                    update.put("contract_status", 4);
                }
                if ("2".equals(Util.null2String(ufContractInfoDTO.getSignedType()))) {
                    update.put("contract_status", 4);
                    //					 仅对方签署完成后，添加用户信息
                    //		        获取配置表信息
                    FaDaDaConfigDTO faDaDaConfigDTO =
                            faDDContractMapping.queryConfig(
                                    String.valueOf(ufContractInfoDTO.getWorkflowType()), 4);
                    RecordSet rs = new RecordSet();
                    String userInfo = ufContractInfoDTO.getUserInfo();
                    User user = JSON.parseObject(userInfo, new TypeReference<User>() {
                    });
                    //		获取流程中的合同字段的文档目录id
                    rs.executeQuery(
                            "select formid from workflow_base where id = ?", ufContractInfoDTO.getWorkflowType());
                    String formId = Util.recordeSet2Entity(rs, String.class);
                    String query =
                            "select doccategory from workflow_fileupload where fieldid = (select id from workflow_billfield where fieldname = ? and billid = ?)";
                    rs.executeQuery(query, faDaDaConfigDTO.getContractDoc(), formId);
                    String docCategorys = Util.null2String(Util.recordeSet2Entity(rs, String.class));
                    if (StringUtils.isNullOrEmpty(docCategorys)) {
                        query = "select doccategory from workflow_base where id = ?";
                        rs.executeQuery(query, ufContractInfoDTO.getWorkflowType());
                        rs.next();
                        docCategorys = Util.null2String(rs.getString(1));
                    }
                    if (StringUtils.isNullOrEmpty(docCategorys)) {
                        docCategorys = ",,1";
                    }
                    //		            String[] docSplit = docCategorys.split(",");
                    //		            String category = docSplit[docSplit.length - 1];
                    //		            下载合同到文件服务器中
                    String docIds = "";
                    try {
                        docIds = downloadContract2FileSystem(ufContractInfoDTO, docCategorys, user);
                    } catch (Exception e) {
                        toolUtil.writeErrorLog("创建文档发生错误：" + e);
                    }
                    toolUtil.writeDebuggerLog("生成的文档的id：" + docIds);
                    //		             将id保存到流程字段中
                    PrepSqlResultImpl sqlResult =
                            Util.createSqlBuilder()
                                    .updateSql(
                                            ufContractInfoDTO.getWorkflowMainTable(),
                                            ParaMap.create().put(faDaDaConfigDTO.getContractDoc(), docIds),
                                            Util.createPrepWhereImpl()
                                                    .whereAnd("id")
                                                    .whereEqual(ufContractInfoDTO.getMainId()));
                    toolUtil.writeDebuggerLog(sqlResult.getSqlStr() + "，参数：" + sqlResult.getArgs());
                    rs.executeUpdate(sqlResult.getSqlStr(), sqlResult.getArgs());
                }
            }
        } else {
            //		    全部合同一起发送的签署信息
            //			直接合同已签署+1
            update.put("signed_num", ufContractInfoDTO.getSignedNum() + 1);
            //			如果已签文件数等于需要签署的合同数乘以合同文件数相等，则代表对方已经签署完毕
            if (ufContractInfoDTO.getSignedNum() + 1
                    == ufContractInfoDTO.getShouldSignedNum()
                    * ufContractInfoDTO.getSingleContractFileNum()) {
                update.put("contract_status", 3);
                //		判断是否控制签署规则 1-仅本方签署，2-仅对方签署，3-都签署
                if ("1".equals(Util.null2String(ufContractInfoDTO.getSignedType()))) {
                    update.put("contract_status", 4);
                }
                if ("2".equals(Util.null2String(ufContractInfoDTO.getSignedType()))) {
                    update.put("contract_status", 4);
                    //					 仅对方签署完成后，添加用户信息
                    //		        获取配置表信息
                    FaDaDaConfigDTO faDaDaConfigDTO =
                            faDDContractMapping.queryConfig(
                                    String.valueOf(ufContractInfoDTO.getWorkflowType()), 4);
                    RecordSet rs = new RecordSet();
                    String userInfo = ufContractInfoDTO.getUserInfo();
                    User user = JSON.parseObject(userInfo, new TypeReference<User>() {
                    });
                    //		获取流程中的合同字段的文档目录id
                    rs.executeQuery(
                            "select formid from workflow_base where id = ?", ufContractInfoDTO.getWorkflowType());
                    String formId = Util.recordeSet2Entity(rs, String.class);
                    String query =
                            "select doccategory from workflow_fileupload where fieldid = (select id from workflow_billfield where fieldname = ? and billid = ?)";
                    rs.executeQuery(query, faDaDaConfigDTO.getContractDoc(), formId);
                    String docCategorys = Util.null2String(Util.recordeSet2Entity(rs, String.class));
                    if (StringUtils.isNullOrEmpty(docCategorys)) {
                        query = "select doccategory from workflow_base where id = ?";
                        rs.executeQuery(query, ufContractInfoDTO.getWorkflowType());
                        rs.next();
                        docCategorys = Util.null2String(rs.getString(1));
                    }
                    if (StringUtils.isNullOrEmpty(docCategorys)) {
                        docCategorys = ",,1";
                    }
                    //		            String[] docSplit = docCategorys.split(",");
                    //		            String category = docSplit[docSplit.length - 1];
                    //		            下载合同到文件服务器中
                    String docIds = "";
                    try {
                        docIds = downloadContract2FileSystem(ufContractInfoDTO, docCategorys, user);
                    } catch (Exception e) {
                        toolUtil.writeErrorLog("创建文档发生错误：" + e);
                    }
                    toolUtil.writeDebuggerLog("生成的文档的id：" + docIds);
                    //		             将id保存到流程字段中
                    PrepSqlResultImpl sqlResult =
                            Util.createSqlBuilder()
                                    .updateSql(
                                            ufContractInfoDTO.getWorkflowMainTable(),
                                            ParaMap.create().put(faDaDaConfigDTO.getContractDoc(), docIds),
                                            Util.createPrepWhereImpl()
                                                    .whereAnd("id")
                                                    .whereEqual(ufContractInfoDTO.getMainId()));
                    toolUtil.writeDebuggerLog(sqlResult.getSqlStr() + "，参数：" + sqlResult.getArgs());
                    rs.executeUpdate(sqlResult.getSqlStr(), sqlResult.getArgs());
                }
            }
        }

        //		更新状态
        PrepSqlResultImpl sqlResult =
                Util.createSqlBuilder()
                        .updateSql(
                                "uf_contract_info",
                                update,
                                Util.createPrepWhereImpl().whereAnd("id").whereEqual(ufContractInfoDTO.getId()));
        RecordSet rs = new RecordSet();
        toolUtil.writeDebuggerLog(
                String.format(
                        "合同签署回调，更新合同状态，更新语句{%s},更新参数{%s}", sqlResult.getSqlStr(), sqlResult.getArgs()));
        rs.executeUpdate(sqlResult.getSqlStr(), sqlResult.getArgs());
        //		查询合同状态，更新明细表
    /*	Map<String,Object> data = new HashMap<>();
    		data.put("contractNo","6a265befb3944d93a7a8b32b8d5ca33d");
    		Map<String, Object> faResult = null;
    		try {
    			faResult = FaDDRequestUtils.queryDetailContractStatus(data);
    			String code = Util.null2String(faResult.get("code"));
    			if(!"200".equals(code)){
    				throw new RuntimeException("查询合同失败，失败原因：" + faResult);
    			}
    			Map<String,Object> resultData = (Map<String, Object>) faResult.get("data");
    			List<Map<String, Object>> contractSignerList = (List<Map<String, Object>>) resultData.get("contractSignerList");
    			for (Map<String, Object> signer : contractSignerList) {
    				if("-1".equals(signer.get("isSender"))){
    					continue;
    				}
    				String customerId = Util.null2String(signer.get("customerId"));
    				String signStatus = Util.null2String(signer.get("signStatus"));
    				if(!"1".equals(signStatus)){
    					continue;
    				}
    //				更新数据库
    				update.clear();
    				update.put("signed_status",2);
    //				查询明细表id
    			}
    		} catch (JsonProcessingException e) {
    			e.printStackTrace();
    			toolUtil.writeErrorLog("查询合同失败，失败原因：" + e);
    		}*/
    }

    /**
     * 查询下一个合同方并发起合同签署
     *
     * @param ufContractInfoDTO
     */
    private void nextContractSigned(UfContractInfoDTO ufContractInfoDTO) {
        String query =
                "select * from "
                        + ufContractInfoDTO.getWorkflowDetailTable()
                        + " where mainid = ? and signed_status is null";
        RecordSet rs = new RecordSet();
        rs.executeQuery(query, ufContractInfoDTO.getMainId());
        List<Map<String, Object>> detailMaps = Util.recordSet2MapList(rs);
        toolUtil.writeDebuggerLog("查询到明细数据：" + JSON.toJSONString(detailMaps));
        query = "select * from " + ufContractInfoDTO.getWorkflowMainTable() + " where requestid = ?";
        RecordSet rs1 = new RecordSet();
        rs1.executeQuery(query, ufContractInfoDTO.getWorkflowRequestId());
        Map<String, Object> mainMap = Util.recordSet2Map(rs1);
        if (mainMap == null) {
            toolUtil.writeErrorLog("mainMap 查询到null -------> " + JSON.toJSONString(ufContractInfoDTO));
            throw new RuntimeException("mainMap查询到null!");
        }
        //		        获取配置表信息
        FaDaDaConfigDTO faDaDaConfigDTO =
                faDDContractMapping.queryConfig(String.valueOf(ufContractInfoDTO.getWorkflowType()), 3);
        //              查询接口配置树形结构
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfigTree(faDaDaConfigDTO.getParamsConfig());
        //		查询签署数据
        List<Map<String, Object>> dataArr =
                getDataArr(
                        ufContractInfoDTO.getWorkflowRequestId(),
                        String.valueOf(ufContractInfoDTO.getWorkflowType()),
                        ufContractInfoDTO.getWorkflowMainTable(),
                        ufContractInfoDTO.getWorkflowDetailTable(),
                        detailMaps);
        //				处理数据
        List<Map<String, Object>> maps = objectAndListHandle(apiConfigMainDTO.getDetails(), dataArr);
        if (maps == null) {
            toolUtil.writeDebuggerLog("service签署合同错误，错误原因：maps为null!");
            throw new RuntimeException("service签署合同错误，错误原因：maps为null！");
        }
        if (maps.size() == 0 || maps.size() <= 1) {
            return;
        }
        Map<String, Object> updateData = new HashMap<>();
        Map<String, Object> map = maps.get(1);
        //		如果进行控制签署规则
        if (faDaDaConfigDTO.getSignedType() == 1) {
            if (Integer.parseInt(Util.null2String(mainMap.get(faDaDaConfigDTO.getFieldControl1())))
                    == faDaDaConfigDTO.getOnlyOther()) {
                //				仅对方签署
                if (maps.size() == 1) {
                    //					map.put("signType", 1);
                    //					如果是最后一个人了，就直接归档
                    map.put("autoArchive", 1);
                }
            }
        }
    /*		if (faDaDaConfigDTO.getSignedType() == 1) {
    //			需要控制签署规则
    			if (Integer.parseInt(Util.null2String(mainMap.get(faDaDaConfigDTO.getFieldControl1()))) == faDaDaConfigDTO.getOnlyOther()) {
    //				只需要对方签署
    				map.put("autoArchive", 1);
    			}
    //			双方签署
    		}*/
        //		签署下一次
        toolUtil.writeDebuggerLog("下一个供应商签署合同，签署数据：" + JSON.toJSONString(map));
        List<Map<String, Object>> resultList = signedRequest(map, apiConfigMainDTO);
        List<String> signedList = new ArrayList<>();
//            遍历将数据保存到合同信息表中
        for (Map<String, Object> result : resultList) {
            signedList.add(String.valueOf(result.get("signerUrl")));
        }
//			将合同签署地址保存到建模信息中
        updateData.put("contract_signed_url", String.join(" ; ", signedList));
        //			    将合同签署信息更新到合同信息表中
        updateData.put("single_signed_num", 0);
        PrepSqlResultImpl sqlResult =
                Util.createSqlBuilder()
                        .updateSql(
                                contractInfoTable,
                                updateData,
                                Util.createPrepWhereImpl()
                                        .whereAnd("workflow_request_id")
                                        .whereEqual(ufContractInfoDTO.getWorkflowRequestId()));
        rs.executeUpdate(sqlResult.getSqlStr(), sqlResult.getArgs());
        updateData.clear();
        //			    更新明细表合同信息  明细表添加字段，signed_status（合同方签署状态）
        //			    签署状态，1 已发送待签署，2 已签蜀
        updateData.put("signed_status", 1);
        sqlResult =
                Util.createSqlBuilder()
                        .updateSql(
                                ufContractInfoDTO.getWorkflowDetailTable(),
                                updateData,
                                Util.createPrepWhereImpl()
                                        .whereAnd("id")
                                        .whereEqual(String.valueOf(map.get("id"))));
        rs.executeUpdate(sqlResult.getSqlStr(), sqlResult.getArgs());
    }

    /**
     * 合同签署发送请求
     *
     * @param map
     * @param apiConfigMainDTO
     */
    private List<Map<String, Object>> signedRequest(Map<String, Object> map, ApiConfigMainDTO apiConfigMainDTO) {
        String contractNos = Util.null2String(map.get("contractNo"));
        String[] split = contractNos.split(",");
        List<Map<String, Object>> resultList = new ArrayList<>();
        //		RecordSet rs = new RecordSet();
        for (String s : split) {
            map.put("contractNo", s);
            ResponeVo responeVo = FaDDRequestUtils.signedContract(map, apiConfigMainDTO.getApiUrl());
            Map<String, Object> response = null;
            try {
                response = responeVo.getEntityMap();
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            if (!"200".equals(response.get("code"))) {
                toolUtil.writeDebuggerLog("法大大接口签署合同失败！");
                throw new RuntimeException("法大大接口签署合同失败!");
            }
            resultList.add((Map<String, Object>) response.get("data"));
        }
        return resultList;
    }

    /**
     * 查询合同的状态信息
     *
     * @param requestId
     * @return
     */
    public Map<String, Object> querySignedStatus(String requestId) {
        //		查询合同状态
        String query = "select * from " + contractInfoTable + " where workflow_request_id = ?";
        RecordSet rs = new RecordSet();
        rs.executeQuery(query, requestId);
        Map<String, Object> result = Util.recordSet2Map(rs);
        this.toolUtil.writeDebuggerLog(result.toString());
        boolean isAllSinged = false;
        boolean isSingedOneself = false;
        if (result == null) {
            toolUtil.writeDebuggerLog("查询到状态为null；sql：" + query + " ---> " + requestId);
            return ParaMap.create().put("isAllSinged", false).put("isSingedOneself", false);
        }
        //		等待对方签署
    /*		if("2".equals(result.get("contract_status"))){
    	isAllSinged = false;
    }*/
        //		等待我方签署
        if ("3".equals(Util.null2String(result.get("contract_status")))) {
            isAllSinged = true;
        }
        //		签署完毕
        if ("4".equals(Util.null2String(result.get("contract_status")))) {
            isAllSinged = true;
            isSingedOneself = true;
        }
        return ParaMap.create().put("isAllSinged", isAllSinged).put("isSingedOneself", isSingedOneself);
    }

    public void signedContractOwn(String requestId, User user) {
        //		查询合同信息
        UfContractInfoDTO ufContractInfoDTO =
                faDDContractMapping.queryContractInfoByRequestId(requestId);
        //		        获取配置表信息
        FaDaDaConfigDTO faDaDaConfigDTO =
                faDDContractMapping.queryConfig(String.valueOf(ufContractInfoDTO.getWorkflowType()), 4);
        //              查询接口配置树形结构
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfigTree(faDaDaConfigDTO.getParamsConfig());
        //		查询签署数据
        List<Map<String, Object>> dataArr =
                getDataArr(
                        ufContractInfoDTO.getWorkflowRequestId(),
                        String.valueOf(ufContractInfoDTO.getWorkflowType()),
                        ufContractInfoDTO.getWorkflowMainTable(),
                        ufContractInfoDTO.getWorkflowDetailTable());
        //				处理数据
        List<Map<String, Object>> maps = objectAndListHandle(apiConfigMainDTO.getDetails(), dataArr);
        if (maps == null) {
            toolUtil.writeErrorLog("service签署合同错误，错误原因：maps为null!");
            throw new RuntimeException("service签署合同错误，错误原因：maps为null！");
        }
        if (maps.size() == 0) {
            return;
        }
        Map<String, Object> data = maps.get(0);
        String contractNos = String.valueOf(data.get("contractNo"));
        String[] split = contractNos.split(",");
        List<String> downloadUrlList = new ArrayList<>();
        List<String> viewUrlList = new ArrayList<>();
        for (String s : split) {
            data.put("contractNo", s);
            ResponeVo responeVo = FaDDRequestUtils.signedContract(data, apiConfigMainDTO.getApiUrl());
            Map<String, Object> response = null;
            try {
                response = responeVo.getEntityMap();
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            if (!"200".equals(response.get("code"))) {
                this.toolUtil.writeErrorLog("签署参数：" + responeVo.getEntityString());
                throw new RuntimeException("本方签署失败！法大大请求接口错误！");
            } else {
                Map<String, Object> result = (Map<String, Object>) response.get("data");
                downloadUrlList.add(Util.null2String(result.get("downloadUrl")));
                viewUrlList.add(Util.null2String(result.get("viewUrl")));
            }
        }
        //		更新合同状态
        RecordSet rs = new RecordSet();
        Map<String, Object> update = new HashMap<>();
        update.put("contract_status", 4);
        update.put("contract_view_url", String.join(";", viewUrlList));
        update.put("contract_down_url", String.join(";", downloadUrlList));
        PrepSqlResultImpl sqlResult =
                Util.createSqlBuilder()
                        .updateSql(
                                contractInfoTable,
                                update,
                                Util.createPrepWhereImpl().whereAnd("workflow_request_id").whereEqual(requestId));
        toolUtil.writeDebuggerLog(sqlResult.getSqlStr() + "，参数：" + sqlResult.getArgs());
        rs.executeUpdate(sqlResult.getSqlStr(), sqlResult.getArgs());
        //		获取流程中的合同字段的文档目录id
        rs.executeQuery(
                "select formid from workflow_base where id = ?", ufContractInfoDTO.getWorkflowType());
        String formId = Util.recordeSet2Entity(rs, String.class);
        String query =
                "select doccategory from workflow_fileupload where fieldid = (select id from workflow_billfield where fieldname = ? and billid = ?)";
        rs.executeQuery(query, faDaDaConfigDTO.getContractDoc(), formId);
        String docCategorys = Util.null2String(Util.recordeSet2Entity(rs, String.class));
        if (StringUtils.isNullOrEmpty(docCategorys)) {
            query = "select doccategory from workflow_base where id = ?";
            rs.executeQuery(query, ufContractInfoDTO.getWorkflowType());
            rs.next();
            docCategorys = Util.null2String(rs.getString(1));
        }
        if (StringUtils.isNullOrEmpty(docCategorys)) {
            docCategorys = ",,1";
        }
        //		String[] docSplit = docCategorys.split(",");
        //		String category = docSplit[docSplit.length - 1];
        //		下载合同到文件服务器中
        String docIds = "";
        try {
            docIds = downloadContract2FileSystem(ufContractInfoDTO, docCategorys, user);
        } catch (Exception e) {
            toolUtil.writeErrorLog("创建文档发生错误：" + e);
        }
        toolUtil.writeDebuggerLog("生成的文档的id：" + docIds);
        //		将id保存到流程字段中
        sqlResult =
                Util.createSqlBuilder()
                        .updateSql(
                                ufContractInfoDTO.getWorkflowMainTable(),
                                ParaMap.create().put(faDaDaConfigDTO.getContractDoc(), docIds),
                                Util.createPrepWhereImpl()
                                        .whereAnd("id")
                                        .whereEqual(ufContractInfoDTO.getMainId()));
        toolUtil.writeDebuggerLog(sqlResult.getSqlStr() + "，参数：" + sqlResult.getArgs());
        rs.executeUpdate(sqlResult.getSqlStr(), sqlResult.getArgs());
    }

    public String downloadContract2FileSystem(
            UfContractInfoDTO ufContractInfoDTO, String category, User user) {

    /*	ImageFileManager fileManager = new ImageFileManager();
    int fileId = fileManager.saveImageFileByInputStream(downloadContract(ufContractInfoDTO.getContractNo(),
    		String.valueOf(ufContractInfoDTO.getWorkflowType())), ufContractInfoDTO.getFileName());*/
        //		 获取配置表信息
        FaDaDaConfigDTO faDaDaConfigDTO =
                faDDContractMapping.queryConfig(String.valueOf(ufContractInfoDTO.getWorkflowType()), 5);
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfig(faDaDaConfigDTO.getParamsConfig());
        String contractNos = Util.null2String(ufContractInfoDTO.getContractNo());
        String[] split = contractNos.split(",");
        List<String> docIds = new ArrayList<>();
        for (String contractNo : split) {
            //			InputStream inputStream = downloadContract(s,
            // String.valueOf(ufContractInfoDTO.getWorkflowType()));
            Map<String, Object> data = new HashMap<>();
            data.put("contractNo", contractNo);
            AtomicReference<InputStream> content = new AtomicReference<>();
            FaDDRequestUtils.downContract(
                    data,
                    response -> {
                        HttpEntity entity = response.getEntity();
                        if (response.getStatusLine().getStatusCode() != 200) {
                            throw new RuntimeException("法大大请求接口错误！");
                        }
                        try {
                            content.set(entity.getContent());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        byte[] byteArray = null;
                        try {
                            byteArray = IOUtils.toByteArray(content.get());
                        } catch (IOException e) {
                            e.printStackTrace();
                            toolUtil.writeErrorLog("文件流处理错误，将inputStream转换为byte数组出错：" + e);
                        }
                        this.toolUtil.writeErrorLog(ufContractInfoDTO.toString());
                        String base64 = Base64Utils.encode(byteArray);
                        FileProcessor fileProcessor = new FileProcessor();
                        //				toolUtil.writeDebuggerLog("base64：" + "base64:" + base64);
                        toolUtil.writeDebuggerLog("category：" + category);
                        //				toolUtil.writeDebuggerLog("user：" + JSON.toJSONString(user));
                        toolUtil.writeDebuggerLog("fileName：" + ufContractInfoDTO.getFileName());
                        docIds.add(
                                String.valueOf(
                                        fileProcessor.Process(
                                                "base64:" + base64, category, user, ufContractInfoDTO.getFileName())));
                    },
                    apiConfigMainDTO.getApiUrl());
        }
        return String.join(",", docIds);
    }

    public InputStream downloadContract(String contractNo, String workflowId) {
        //		 获取配置表信息
        FaDaDaConfigDTO faDaDaConfigDTO = faDDContractMapping.queryConfig(workflowId, 5);
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfig(faDaDaConfigDTO.getParamsConfig());
        Map<String, Object> data = new HashMap<>();
        data.put("contractNo", contractNo);
        AtomicReference<InputStream> content = new AtomicReference<>();
        FaDDRequestUtils.downContract(
                data,
                response -> {
                    HttpEntity entity = response.getEntity();
                    if (response.getStatusLine().getStatusCode() != 200) {
                        throw new RuntimeException("法大大请求接口错误！");
                    }
                    try {
                        content.set(entity.getContent());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                },
                apiConfigMainDTO.getApiUrl());
        return content.get();
    }

    /**
     * 直接从法大大系统下载文件
     *
     * @param ufContractInfoDTO 合同相关信息
     * @return
     */
    public StreamingOutput download4mFDD(UfContractInfoDTO ufContractInfoDTO) {
        //		 获取配置表信息
        FaDaDaConfigDTO faDaDaConfigDTO =
                faDDContractMapping.queryConfig(String.valueOf(ufContractInfoDTO.getWorkflowType()), 5);
        ApiConfigMainDTO apiConfigMainDTO = Util.queryApiConfig(faDaDaConfigDTO.getParamsConfig());
        //		查询合同信息
        //		UfContractInfoDTO ufContractInfoDTO =
        // faDDContractMapping.queryContractInfoByRequestId(requestId);
        String contractNos = Util.null2String(ufContractInfoDTO.getContractNo());
        String fileNames = Util.null2String(ufContractInfoDTO.getFileName());
        String[] contractNoArr = contractNos.split(",");
        String[] fileNameArr = fileNames.split(",");
        toolUtil.writeDebuggerLog("下载合同download4mFDD！");
        if (contractNoArr.length >= 2) {
            //			多个文件，需要下载压缩包
            return outputStream -> {
                ZipOutputStream zipOut = new ZipOutputStream(outputStream);
                int catchLen = 10 * 1024;
                for (int i = 0; i < contractNoArr.length; i++) {
                    //					InputStream inputStream = downloadContract(contractNoArr[i],
                    // String.valueOf(ufContractInfoDTO.getWorkflowType()));
                    Map<String, Object> data = new HashMap<>();
                    data.put("contractNo", contractNoArr[i]);
                    AtomicReference<InputStream> content = new AtomicReference<>();
                    int finalI = i;
                    FaDDRequestUtils.downContract(
                            data,
                            response -> {
                                HttpEntity entity = response.getEntity();
                                if (response.getStatusLine().getStatusCode() != 200) {
                                    throw new RuntimeException("法大大请求接口错误！");
                                }
                                try {
                                    content.set(entity.getContent());
                                    zipOut.putNextEntry(new ZipEntry(fileNameArr[finalI]));
                                    byte[] buffer = new byte[catchLen];
                                    int len = 0;
                                    while ((len = content.get().read(buffer)) != -1) {
                                        zipOut.write(buffer, 0, len);
                                    }
                                    content.get().close();
                                    zipOut.closeEntry();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    toolUtil.writeErrorLog("文件压缩处理出现问题！" + e);
                                }
                            },
                            apiConfigMainDTO.getApiUrl());
                }
                zipOut.flush();
                zipOut.close();
                outputStream.flush();
                outputStream.close();
            };
        }
        return outputStream -> {
            toolUtil.writeDebuggerLog("download4mFDD单文件下载！");
            //			InputStream inputStream =
            // downloadContract(contractNos,String.valueOf(ufContractInfoDTO.getWorkflowType()));
            Map<String, Object> data = new HashMap<>();
            data.put("contractNo", contractNos);
            AtomicReference<InputStream> content = new AtomicReference<>();
            FaDDRequestUtils.downContract(
                    data,
                    response -> {
                        HttpEntity entity = response.getEntity();
                        if (response.getStatusLine().getStatusCode() != 200) {
                            throw new RuntimeException("法大大请求接口错误！");
                        }
                        try {
                            content.set(entity.getContent());
                            int catchLen = 10 * 1024;
                            byte[] buffer = new byte[catchLen];
                            int len = 0;
                            while ((len = content.get().read(buffer)) != -1) {
                                outputStream.write(buffer, 0, len);
                            }
                            content.get().close();
                            outputStream.flush();
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                            toolUtil.writeErrorLog("单文件下载处理出现问题！" + e);
                        }
                    },
                    apiConfigMainDTO.getApiUrl());
        };
    }

    public void pushAPush(String requestId) {
        toolUtil.writeDebuggerLog("进入催一催方法===================");
        UfContractInfoDTO ufContractInfoDTO = faDDContractMapping.queryContractInfoByRequestId(requestId);
        toolUtil.writeDebuggerLog("获取到合同数据：" + JSON.toJSONString(ufContractInfoDTO));
        String signedUrls = Util.null2String(ufContractInfoDTO.getContractSignedUrl());
        PushAPushEmailEntity pushAPushEmailEntity = queryEmailInfo(ufContractInfoDTO.getWorkflowType(),
                ufContractInfoDTO.getWorkflowRequestId());
        toolUtil.writeDebuggerLog("获取到邮件信息数据：" + JSON.toJSONString(pushAPushEmailEntity));
        String content = pushAPushEmailEntity.getEmailContent().replaceAll("#\\{info.signedUrls}", signedUrls);
        toolUtil.writeDebuggerLog("contnet:" + content);
        try {
            EmailWorkRunnable.threadModeReminder(pushAPushEmailEntity.getEmailAddress(), "", "",
                    pushAPushEmailEntity.getEmailTitle(),
                    content);
        } catch (Exception e) {
            toolUtil.writeDebuggerLog(e.toString());
        }
        toolUtil.writeDebuggerLog("结束催一催方法===================");
    }

    private PushAPushEmailEntity queryEmailInfo(int workflowType, String requestId) {
        PushAPushEmailEntity pushAPushEmailEntity = faDDContractMapping.queryEmailInfo(workflowType);
        Map<String, Object> workflowData = getWorkflowData(String.valueOf(workflowType), requestId);
        toolUtil.writeDebuggerLog("获取到邮件配置参数：" + JSON.toJSONString(pushAPushEmailEntity));
        toolUtil.writeDebuggerLog("查询到的数据：===>  " + JSON.toJSONString(workflowData));
        String parsingTitle = parsingValue(pushAPushEmailEntity.getEmailTitle(), workflowData);
        toolUtil.writeDebuggerLog("parsingTitle解析后的值：" + parsingTitle);
        pushAPushEmailEntity.setEmailTitle(parsingTitle);
        String parsingEmail = parsingValue(pushAPushEmailEntity.getEmailAddress(), workflowData);
        toolUtil.writeDebuggerLog("parsingEmail解析后的值：" + parsingEmail);
        pushAPushEmailEntity.setEmailAddress(parsingEmail);
        try {
            String parsingContent = parsingValue(pushAPushEmailEntity.getEmailContent(), workflowData);
            toolUtil.writeDebuggerLog("parsingContent解析后的值：" + parsingContent);
            pushAPushEmailEntity.setEmailContent(parsingContent);
        } catch (Exception e) {
            toolUtil.writeDebuggerLog("解析出错：" + e.toString());
        }
        return pushAPushEmailEntity;
    }

    public String parsingValue(String str, Map<String, Object> workflowData) {
        String regEx = "\\$\\{(?<key>\\S+?)}";
        Pattern compile = Pattern.compile(regEx);
        Matcher matcher = compile.matcher(str);
        String parsingValue = str;
        parsingValue = parsingValue.replaceAll("\\$\\{sys\\.data}", Util.getTime("yyyy-MM-dd"));
        parsingValue = parsingValue.replaceAll("\\$\\{sys\\.time}", Util.getTime("HH:mm:ss"));
        parsingValue = parsingValue.replaceAll("\\$\\{sys\\.dataTime}", Util.getTime("yyyy-MM-dd HH:mm:ss"));
        while (matcher.find()) {
            String key = matcher.group("key");
            String value = Util.null2String(workflowData.get(key));
            parsingValue = parsingValue.replaceFirst(regEx, value);
        }
        regEx = "#sql\\{\\{(?<key>(\\S\\s)+?)}}";
        compile = Pattern.compile(regEx);
        matcher = compile.matcher(str);
        while (matcher.find()) {
            String key = matcher.group("key");
            String value = parsingSql(key, workflowData);
            parsingValue = parsingValue.replaceFirst(regEx, value);
        }
        return parsingValue;
    }

    private String parsingSql(String str, Map<String, Object> workflowData) {
        RecordSet rs = new RecordSet();
        String sqlRegEx = "#\\{(?<key>\\S+?)}";
        Pattern sqlCompile = Pattern.compile(sqlRegEx);
        Matcher sqlMatcher = sqlCompile.matcher(str);
        String parsingSql = str;
        parsingSql = parsingSql.replaceAll("#\\{sys\\.data}", "'" + Util.getTime("yyyy-MM-dd") + "'");
        parsingSql = parsingSql.replaceAll("#\\{sys\\.time}", "'" + Util.getTime("HH:mm:ss") + "'");
        parsingSql = parsingSql.replaceAll("#\\{sys\\.dataTime}", "'" + Util.getTime("yyyy-MM-dd HH:mm:ss") + "'");
        List<String> args = new ArrayList<>();
        while (sqlMatcher.find()) {
            String key = sqlMatcher.group("key");
            String value = Util.null2String(workflowData.get(key));
            parsingSql = parsingSql.replaceFirst(sqlRegEx, "?");
            args.add(value);
        }
        String value = "";
        if (str.toLowerCase().trim().startsWith("select")) {
            rs.executeQuery(parsingSql, args);
            if (rs.next()) {
                value = rs.getString(1);
            }
        }
        return value;
    }

    public Map<String, Object> getWorkflowData(String workflowId, String requestId) {
        String queryMainTable = "select base.id,base.workflowname,base.formid,bill.tablename " +
                "from workflow_bill bill join workflow_base base on base.formid = bill.id " +
                "where base.id = ?";
        RecordSet rs = new RecordSet();
        rs.executeQuery(queryMainTable, workflowId);
        String mainTable = "";
        if (rs.next()) {
            mainTable = rs.getString("tablename");
        } else {
            toolUtil.writeDebuggerLog("表查询到数据为null，" + mainTable + "---》" + queryMainTable);
        }
        String queryDetailTable = "select bill.id bill_id, base.workflowname,base.formid " +
                "main_formid,bill.tablename,bill.orderid from workflow_billdetailtable bill " +
                "join workflow_base base on base.formid = bill.billid where base.id = ?";
        rs.executeQuery(queryDetailTable, workflowId);
        List<Map<String, String>> detailTableList = new ArrayList<>();
        while (rs.next()) {
            Map<String, String> map = new HashMap<>();
            map.put("tableName", rs.getString("tablename"));
            map.put("tableOrderId", rs.getString("orderid"));
            detailTableList.add(map);
        }
//        查询主表数据
        String queryMainData = "select * from " + mainTable + " where requestid = ?";
        rs.executeQuery(queryMainData, requestId);
        Map<String, Object> mainData = Util.recordSet2Map(rs);
        if (mainData == null) {
            toolUtil.writeDebuggerLog("查询到数据为null，" + mainData + "---》" + queryMainData);
            return null;
        }
//        查询明细表数据
        for (Map<String, String> detailTable : detailTableList) {
            String queryDetailData = "select * from " + detailTable.get("tableName") + " where mainid = ?";
            rs.executeQuery(queryDetailData, String.valueOf(mainData.get("id")));
            Map<String, Object> detailData = Util.recordSet2Map(rs);
            if (detailData == null) {
                continue;
            }
            for (Map.Entry<String, Object> entry : detailData.entrySet()) {
                mainData.put("detail_" + detailTable.get("tableOrderId") + "." + entry.getKey(), entry.getValue());
            }
        }
        mainData.put("requestId", requestId);
        mainData.put("workflowId", workflowId);
        return mainData;
    }

}



